#include "task.h"
#include "mm.h"
#include "assert.h"
#include "string.h"
#include "kernel.h"

extern void* kernel_thread(void* arg);
task_t *task_table[NR_TASKS];

extern task_t *current;

void* t1(void* arg)
{
    int processor_id = 0;
    for (size_t i = 0; i < 500000; i++)
    {
        asm volatile("swapgs;"
                     "mov %%gs:0, %0;"
                     "swapgs;"
                :"=r"(processor_id)::"rax");

        printk_fixed_position(160 * 20, "processor id:%d, t1:%d", processor_id, i);
    }

}

void* t2(void* arg)
{
    int processor_id = 0;
    for (size_t i = 0; i < 500000; i++)
    {
        asm volatile("swapgs;"
                     "mov %%gs:0, %0;"
                     "swapgs;"
                :"=r"(processor_id)::"rax");

        printk_fixed_position(160 * 21, "processor id:%d, t1:%d", processor_id, i);
    }

}

void* t3(void* arg)
{
    int processor_id = 0;
    for (size_t i = 0; i < 500000; i++)
    {
        asm volatile("swapgs;"
                     "mov %%gs:0, %0;"
                     "swapgs;"
                :"=r"(processor_id)::"rax");

        printk_fixed_position(160 * 22, "processor id:%d, t1:%d", processor_id, i);
    }

}

void* t4(void* arg)
{
    int processor_id = 0;
    for (size_t i = 0; i < 500000; i++)
    {
        asm volatile("swapgs;"
                     "mov %%gs:0, %0;"
                     "swapgs;"
                :"=r"(processor_id)::"rax");

        printk_fixed_position(160 * 23, "processor id:%d, t1:%d", processor_id, i);
    }

}

static int find_empty_process()
{
    int i = 0;
    for (i = 0; i < NR_TASKS; i++)
    {
        if (0 == task_table[i])
        {
            return i;
        }
    }
    printk("no empty process\n");
    return -1;
}

task_t * task_create(task_fun_t fun, char* name)
{
    task_t* task = kmalloc(sizeof(task_t));
    task->state = TASK_INIT;
    task->pid = find_empty_process();
    assert(task->pid!= -1);

    task_table[task->pid] = task;
    task->function = fun;
    strcpy(task->name, name);
    task->esp0 = kmalloc(PAGE_SIZE) + PAGE_SIZE;
    task->state = TASK_READY;
    return task;
}

task_fun_t get_task_function(task_t *task)
{
    return task->function;
}

task_context_t *get_task_context(task_t *task)
{
    return &task->context;
}

void task_exit(task_t *task, int exit_code)
{
    for (size_t i = 0; i < NR_TASKS; i++)
    {
        task_t* t = task_table[i];
        if (t == task)
        {
            // printk("task %s exit\n", task->name);
            t->exit_code = exit_code;
            task_table[i] = NULL;
            current = NULL;
            kfree_s(task->esp0, 4096);
            kfree_s(task, sizeof(task_t));
            break;
        }
    }

}

int inc_scheduling_times(task_t *task)
{
    return task->scheduling_times++;
}

int64 get_esp0(task_t* task)
{
    return task->esp0;
}

void set_task_ready(task_t* task)
{
    task->state = TASK_READY;
}

void print_tasks()
{
    for (size_t i = 0; i < NR_TASKS; i++)
    {
        task_t* task = task_table[i];
        if (NULL == task)
        {
            continue;
        }
        char* status = (1 == task->state) ? "running" : "ready";
        printk("[%s] status: %s, sched times: %d, stack: 0x%08x\n", task->name, status, task->scheduling_times, task->esp0);
    }
}

void task_init()
{
    task_create(kernel_thread, "kernel_thread");
}

void int_to_char(int num, char*str)
{
    int i = 0, j, rem, len = 0;
    if (num == 0)
    {
        str[0] = '0';
        str[1] = '\0';
        return;
    }
    while (num != 0)
    {
        rem = num % 10;
        if (rem > 9)
        {
            str[i++] = (rem - 10) + "A";
        }
        else
        {
            str[i++] = rem + '0';
        }
        num = num / 10;
    }
    str[i] = '\0';

    for (j = 0, i =  i - 1; j < i; j++, i--)
    {
        char tmp = str[j];
        str[j] = str[i];
        str[i] = tmp;
    }
}

void* t_function(void* args)
{
    int processor_id = 0;
    task_t* task = NULL;
    for (size_t i = 0; i < 200000; i++)
    {
        asm volatile("swapgs;\n"
                     "mov %%gs:0, %0;\n"
                     "mov %%gs:8, %1;\n"
                     "swapgs;"
                :"=r"(processor_id), "=r"(task)::"rax");

        printk_fixed_position(160 * (20 + task->pid), "[%s]processor id:%d, t1:%d, pid:%d",
                              task->name, processor_id, i, task->pid);
    }

}

void task_test(int size)
{
    for (size_t i = 0; i < size; i++)
    {
        char name[32] = "t";
        char str[2] = {0};
        int_to_char(i, str);
        strcat(name, str);
        printk("%s\n", name);
        task_create(t_function, name);
    }

}